#include "../include/socket.h"
#include "../include/macro.h"
#include <unistd.h>
#include <stdio.h>
#include "../include/my_log.h"
void _socket::add_con_to_kick_map(connection_p con_p)
{
    //组装
    message_head_d *head=new message_head_d;    //如果申请失败了，说明内存不够，想写日志也写不了
    head->iCurrSequence=con_p->icurrentsequence;
    head->con_p=con_p;

    time_t now_time=time(NULL);

    pthread_mutex_lock(&this->kick_mutex);  //加锁
    this->kick_map.insert(std::pair<time_t,message_head_d *>(now_time,head));
    pthread_mutex_unlock(&this->kick_mutex); //解锁

}

//会顺带清空节点内存
void _socket::delete_con_from_kick_map(message_head_d * con)
{
    pthread_mutex_lock(&this->kick_mutex);  //上锁
    //循环查找
    for(auto it=this->kick_map.begin();it!=this->kick_map.end();++it){
        if(it->second==con){
            delete it->second;
            this->kick_map.erase(it);
            break;
        }
    }
    pthread_mutex_unlock(&this->kick_mutex);    //解锁
}



void *_socket::kick_map_check_timeOut_thread(void *_item)
{
    thread_item_for_socket * item=(thread_item_for_socket *)(_item);
    _socket * external_socket=item->external_socket;
    std::multimap<time_t,message_head_d *>::iterator it;    //承载遍历的迭代器
    int gap_of_check_time=external_socket->time_of_check_gap;   //间隔的检测时间
    std::list<message_head_d *> check_time_out_list;
    while(1){
        sleep(external_socket->time_of_check_gap);  //睡觉不要那么频繁
        
        if(external_socket->kick_map_check_thread_running_flag==PRO_END){
            break;
        }
        //检查每一个
        time_t now_time=time(NULL);

        pthread_mutex_lock(&external_socket->kick_mutex);
        it=external_socket->kick_map.begin();
        while(it!=external_socket->kick_map.end()){

            
             //检测失效与否
             if(it->second->con_p->icurrentsequence!=it->second->iCurrSequence){
                //连接已经失效了，那么，erase后直接delete后即可
                delete it->second;
                it=external_socket->kick_map.erase(it);
                continue;

            }
            //判断连接是否强制退出
            if(external_socket->is_force_to_kick){
                if(it->first+external_socket->time_of_force_kick<=now_time){
                    //到点了
                    external_socket->add_con_to_recycle(it->second->con_p);
                    delete it->second;
                    it=external_socket->kick_map.erase(it);

                    continue;
                }
            }

            //拿取出需要检测的节点，去检测
            if(it->first+external_socket->time_of_check_gap<=now_time){
               
                check_time_out_list.push_back(it->second);
                it=external_socket->kick_map.erase(it);        // 拿取出来
                
            }else{
                break;  //找到第一个不符合的就可以了
            }

        }
        pthread_mutex_unlock(&external_socket->kick_mutex);

        //去真正的检测，在这个过程中，由于已经解锁了，那么是不是可能有新的加入呢?
        if(check_time_out_list.size()>0){

            external_socket->doing_check_is_timeout(now_time,check_time_out_list);  //传的是引用
            //这里边可能有没有超时的连接，那么需要加入
            pthread_mutex_lock(&external_socket->kick_mutex);
            message_head_d * tmp_data;
            //这些重新放入
            while(!check_time_out_list.empty()){        
                tmp_data=check_time_out_list.front();
                external_socket->kick_map.insert(std::make_pair(now_time+gap_of_check_time,tmp_data));
                check_time_out_list.pop_front();
            }
            pthread_mutex_unlock(&external_socket->kick_mutex);
        }

        
        
    }
    //将所有都处理掉---放入到待回收队列中去,执行这个的时候，已经确保不会有新的连接，那么就不需要上锁
    external_socket->clear_kick_map();

    return nullptr;
}

void _socket::doing_check_is_timeout(time_t now, std::list<message_head_d *> & l)
{
    
    auto it=l.begin();
    while(it!=l.end()){
        //判断是否超时
        if((*it)->con_p->last_ping+3*time_of_check_gap<=now){
            //真的超时了
            //放入待释放连接队列里，
            my_log::get_log_instance()->write_log(LOG_INFO,0,"成功将一个超时连接 ip:%s port: %d 放入待回收队列中去 ",inet_ntoa((*it)->con_p->opposite_addr.sin_addr),ntohs((*it)->con_p->opposite_addr.sin_port));
            this->add_con_to_recycle((*it)->con_p); 
            delete (*it);   //外面放进来，并没有delete释放,所以这里要释放
            it=l.erase(it);
            
        }else{
            ++it;   //
        }
    }


}

void _socket::clear_kick_map()
{

    std::multimap<time_t,message_head_d *>::iterator it; 
    it=kick_map.begin();
    while(it!=kick_map.end()){

        //将还有的放入待回收队列中去------踢出所有用户
        add_con_to_recycle(it->second->con_p);
        delete it->second;
        it=kick_map.erase(it);
    }

}